package com.yf.train.modules.train.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yf.base.api.api.dto.PagingReqDTO;
import com.yf.base.api.exception.ServiceException;
import com.yf.base.utils.BeanMapper;

import com.yf.repo.enums.QuType;
import com.yf.repo.modules.qu.dto.QuAnswerDTO;
import com.yf.repo.modules.qu.entity.Qu;
import com.yf.repo.modules.qu.service.QuAnswerService;
import com.yf.repo.modules.qu.service.QuService;
import com.yf.repo.modules.repo.entity.Repo;
import com.yf.repo.modules.repo.service.RepoService;
import com.yf.train.modules.train.dto.RepoTrainDTO;
import com.yf.train.modules.train.dto.RepoTrainQuDTO;
import com.yf.train.modules.train.dto.ext.TrainQaDetailDTO;
import com.yf.train.modules.train.dto.ext.TrainQuDetailDTO;
import com.yf.train.modules.train.dto.request.RepoTrainReqDTO;

import com.yf.train.modules.train.entity.RepoTrain;
import com.yf.train.modules.train.entity.RepoTrainQu;
import com.yf.train.modules.train.mapper.RepoTrainMapper;
import com.yf.train.modules.train.service.RepoTrainQuService;
import com.yf.train.modules.train.service.RepoTrainService;

import com.yf.system.modules.user.UserUtils;
import com.yf.system.utils.ListUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
* <p>
* 题库训练业务实现类
* </p>
*
* @author 聪明笨狗
* @since 2022-03-01 18:42
*/
@Service
public class RepoTrainServiceImpl extends ServiceImpl<RepoTrainMapper, RepoTrain> implements RepoTrainService {


    @Autowired
    private RepoTrainQuService repoTrainQuService;

    @Autowired
    private QuService quService;

    @Autowired
    private RepoService repoService;

    @Autowired
    private QuAnswerService quAnswerService;

    @Override
    public IPage<RepoTrainDTO> paging(PagingReqDTO<RepoTrainReqDTO> reqDTO) {
        IPage<RepoTrainDTO> pageData = baseMapper.paging(reqDTO.toPage(), reqDTO.getParams());
        return pageData;
    }

    @Override
    public RepoTrainDTO detail(String id){
        RepoTrain entity = this.getById(id);
        RepoTrainDTO dto = new RepoTrainDTO();
        BeanMapper.copy(entity, dto);
        return dto;
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public String start(RepoTrainDTO repoDTO) {
        QueryWrapper<RepoTrain> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(RepoTrain::getCreateBy, UserUtils.getUserId())
                .eq(RepoTrain::getRepoId, repoDTO.getRepoId())
                .eq(RepoTrain::getMode, repoDTO.getMode())
                .eq(RepoTrain::getState, 0);

        RepoTrain train = this.getOne(wrapper, false);
        boolean clear = false;


        // 判断权限
        Repo repo = repoService.getById(repoDTO.getRepoId());
        if(repo!=null
                && repo.getIsTrain()!=null
                && !repo.getIsTrain()){

            // 清理全部训练记录
            if(train!=null){
                this.finish(train.getId());
            }

            // 抛出异常
            throw new ServiceException("当前题库已关闭训练功能，不能继续训练！");
        }


        // 更新
        if (train != null) {
            train.setUpdateTime(new Date());
            this.update(train, wrapper);
        } else {
            train = new RepoTrain();
            train.setMode(repoDTO.getMode());
            train.setState(0);
            train.setRepoId(repoDTO.getRepoId());
            train.setCreateBy(UserUtils.getUserId());
            this.save(train);
            clear = true;
        }

        // 创建训练题目数据
        repoTrainQuService.build(train.getId(), repoDTO.getRepoId(), repoDTO.getMode(), clear);

        return train.getId();
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public RepoTrainQuDTO fill(TrainQuDetailDTO reqDTO) {
        return this.fill(reqDTO, true);
    }

    @Override
    public RepoTrainDTO findProcess(String repoId) {
        return baseMapper.checkProcess(UserUtils.getUserId(), repoId);
    }

    @Override
    public void finish(String trainId) {

        RepoTrain repo = new RepoTrain();
        repo.setId(trainId);
        repo.setState(1);
        this.updateById(repo);

        // 清理训练细节
        repoTrainQuService.clear(trainId);
    }

    /**
     * 判定及保存答案
     * @param reqDTO
     * @param save
     * @return
     */
    public RepoTrainQuDTO fill(TrainQuDetailDTO reqDTO, boolean save) {


        // 题目信息
        Qu qu = quService.getById(reqDTO.getQuId());
        String quType = qu.getQuType();

        // 单选多选判断，本质是一样的处理
        if (QuType.RADIO.equals(quType) || QuType.MULTI.equals(quType) || QuType.JUDGE.equals(quType)) {
            // 保存和校验
            this.checkAndSave13(reqDTO);
        }

        // 填空题
        if (QuType.FILL.equals(quType)) {
            this.checkAndSave5(reqDTO);
        }

        // 简答题直接正确
        if (QuType.SAQ.equals(quType)) {
            reqDTO.setAnswered(true);
            reqDTO.setIsRight(true);
        }

        // 组合题
        if(QuType.MIX.equals(quType)){
            this.checkAndSave99(reqDTO);
        }


        // 保存全部答案
        if(save) {
            repoTrainQuService.saveAll(reqDTO);
        }

        // 同步训练状态
        this.syncState(reqDTO.getTrainId());

        // 回写结果
        RepoTrainQuDTO respDTO = BeanMapper.map(reqDTO, RepoTrainQuDTO.class);

        return respDTO;
    }


    /**
     * 校验和保存单选、多选、判断题
     * @param reqDTO
     */
    private void checkAndSave13(TrainQuDetailDTO reqDTO) {

        List<TrainQaDetailDTO> answers = reqDTO.getAnswerList();

        // 正确选项
        List<String> rightList = this.rightList(reqDTO.getQuId(), false);

        // 用户回答列表
        List<String> userList = new ArrayList<>();


        // 循环标准答案
        for (TrainQaDetailDTO a : answers) {
            // 选择即用户答案
            if (a.getChecked()!=null && a.getChecked()) {
                userList.add(a.getAnswerId());
            }
        }

        // 是否正确
        boolean right = ListUtils.compareList(false, rightList, userList);

        // 保存用户答案
        reqDTO.setAnswered(!CollectionUtils.isEmpty(userList));
        reqDTO.setIsRight(right);
    }


    /**
     * 校验和保存填空题
     * @param reqDTO
     */
    private void checkAndSave5(TrainQuDetailDTO reqDTO) {

        List<TrainQaDetailDTO> answers = reqDTO.getAnswerList();

        // 正确选项
        List<String> rightList = this.rightList(reqDTO.getQuId(), true);

        // 用户回答列表
        List<String> userList = new ArrayList<>();

        // 循环标准答案
        for (TrainQaDetailDTO a : answers) {
            if (!StringUtils.isBlank(a.getAnswer())) {
                userList.add(a.getAnswer());
            }
        }
        // 是否正确
        boolean right = ListUtils.compareList(false, rightList, userList);
        // 保存用户答案
        reqDTO.setAnswered(true);
        reqDTO.setIsRight(right);
    }

    /**
     * 校验和保存组合题
     * @param reqDTO
     */
    private void checkAndSave99(TrainQuDetailDTO reqDTO){

        List<TrainQuDetailDTO> subList = reqDTO.getSubList();

        boolean right = true;

        for(TrainQuDetailDTO item: subList){
            RepoTrainQuDTO resp = this.fill(item, false);
            if(!resp.getIsRight()){
                right = false;
            }
        }

        reqDTO.setAnswered(true);
        reqDTO.setIsRight(right);
    }


    /**
     * 获取正确列表
     *
     * @param quId
     * @param fill
     * @return
     */
    private List<String> rightList(String quId, boolean fill) {

        // 标准答案
        List<QuAnswerDTO> list = quAnswerService.listByQu(quId);

        // 正确项
        List<String> rightMap = new ArrayList<>();

        for (QuAnswerDTO item : list) {
            if (fill) {
                rightMap.add(item.getContent());
                continue;
            }
            if (item.getIsRight()) {
                rightMap.add(item.getId());
            }
        }
        return rightMap;
    }


    /**
     * 同步训练状态
     *
     * @param trainId
     */
    public void syncState(String trainId) {

        QueryWrapper<RepoTrainQu> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(RepoTrainQu::getChild, false)
                .eq(RepoTrainQu::getTrainId, trainId);

        int total = repoTrainQuService.count(wrapper);
        wrapper.lambda().eq(RepoTrainQu::getAnswered, true);
        int answered = repoTrainQuService.count(wrapper);
        wrapper.lambda().eq(RepoTrainQu::getIsRight, true);
        int right = repoTrainQuService.count(wrapper);

        RepoTrain train = this.getById(trainId);
        train.setTotalCount(total);
        train.setAnswerCount(answered);
        train.setRightCount(right);
        this.updateById(train);
    }

}
